#include "SpeexEncoder.h"
#include "speex/speex.h"
#include <stdio.h>

// uwb = 32khz 1280
// wb = 16khz 640
// nb = 8khz 320



using namespace AgoraClient;

SpeexEncoder::SpeexEncoder(int quality) :
_quality(quality),
_NBencoderState(0),
_WBencoderState(0),
_UWBencoderState(0),
_NBdecoderState(0),
_WBdecoderState(0),
_UWBdecoderState(0)
{
}

SpeexEncoder::~SpeexEncoder()
{
	if (_UWBencoderState)
		speex_encoder_destroy(_UWBencoderState);
	if (_WBencoderState)
		speex_encoder_destroy(_WBencoderState);
	if (_NBencoderState)
		speex_encoder_destroy(_NBencoderState);
	if (_UWBdecoderState)
		speex_decoder_destroy(_UWBdecoderState);
	if (_WBdecoderState)
		speex_decoder_destroy(_WBdecoderState);
	if (_NBdecoderState)
		speex_encoder_destroy(_NBdecoderState);
}

void SpeexEncoder::SetQuality(int quality)
{
	if (quality >= 0)
	{
		_quality = quality;
		if (_UWBencoderState)
			speex_encoder_ctl(_UWBencoderState, SPEEX_SET_QUALITY, &_quality);
		if (_WBencoderState)
			speex_encoder_ctl(_WBencoderState, SPEEX_SET_QUALITY, &_quality);
		if (_NBencoderState)
			speex_encoder_ctl(_NBencoderState, SPEEX_SET_QUALITY, &_quality);
	}
}

int SpeexEncoder::GetQuality(int quality)
{
	return _quality;
}

void *SpeexEncoder::GetEncoder(unsigned short frequence)
{
	if (frequence == 32000)
	{
		if (!_UWBencoderState)
		{
			_UWBencoderState = speex_encoder_init(&speex_uwb_mode);
			speex_encoder_ctl(_UWBencoderState, SPEEX_SET_QUALITY, &_quality);
		}
		return (_UWBencoderState);
	}
	else if (frequence == 16000)
	{
		if (!_WBencoderState)
		{
			_WBencoderState = speex_encoder_init(&speex_wb_mode);
			speex_encoder_ctl(_WBencoderState, SPEEX_SET_QUALITY, &_quality);
		}
		return (_WBencoderState);
	}
	else if (frequence == 8000)
	{
		if (!_NBencoderState)
		{
			_NBencoderState = speex_encoder_init(&speex_nb_mode);
			speex_encoder_ctl(_NBencoderState, SPEEX_SET_QUALITY, &_quality);
		}
		return (_NBencoderState);
	}
	return NULL;
}

void *SpeexEncoder::GetDecoder(unsigned short frequence)
{
	int tmp(1);

	if (frequence == 8000)
	{
		if (!_NBdecoderState)
		{
			_NBdecoderState = speex_decoder_init(&speex_nb_mode);
			 speex_decoder_ctl(_NBdecoderState, SPEEX_SET_ENH, &tmp);
		}
		return (_NBdecoderState);
	}
	else if (frequence == 16000)
	{
		if (!_WBdecoderState)
		{
			_WBdecoderState = speex_decoder_init(&speex_wb_mode);
			 speex_decoder_ctl(_WBdecoderState, SPEEX_SET_ENH, &tmp);
		}
		return (_WBdecoderState);
	}
	else if (frequence == 32000)
	{
		if (!_UWBdecoderState)
		{
			_UWBdecoderState = speex_decoder_init(&speex_uwb_mode);
			 speex_decoder_ctl(_UWBdecoderState, SPEEX_SET_ENH, &tmp);
		}
		return (_UWBdecoderState);
	}
	return NULL;
}


void SpeexEncoder::Encode(IBuffer *bufferIn, IBuffer *bufferOut, unsigned short frequence)
{
	static int count = 0;
	char buffer[1280];
	bool first = true;
	unsigned int nbBytes;
	char nbEncodedData ;
	unsigned int frameSize = (frequence == 32000 ? 1280 : (frequence == 16000 ? 640 : 320));
	void *encoder = GetEncoder(frequence);
	
	SpeexBits bits;



	if (encoder && bufferIn->Size() > frameSize)
	{
	

		int frame_size;
		speex_encoder_ctl(encoder,SPEEX_GET_FRAME_SIZE,&frame_size); 
		nbEncodedData = bufferIn->Size() / frameSize;
		speex_bits_init(&bits);
		while (nbEncodedData > 1)
		{
			speex_bits_reset(&bits);
			speex_encode_int(encoder, (short*)bufferIn->Read(frameSize), &bits);
			nbBytes = speex_bits_write(&bits, buffer, 1280);
			if (first)
			{
				if (nbEncodedData * nbBytes >= bufferOut->SizeMax() - bufferOut->Size())
				{
					bufferIn->Clean();
					bufferOut->Write(0,0);
					return;
					// TODO ERROR
				}
				else
				{
					first = false;
					bufferOut->SetEvent(false);
					bufferOut->Write(&nbEncodedData , 1);
				}

			}
			nbEncodedData--;
			bufferOut->Write(buffer, nbBytes);
		}
		speex_bits_reset(&bits);
		speex_encode_int(encoder,  (short*)bufferIn->Read(frameSize), &bits);
		nbBytes = speex_bits_write(&bits, buffer, 1280);
		if (first)
		{
			if (nbEncodedData * nbBytes >= bufferOut->SizeMax() - bufferOut->Size())
			{
				bufferIn->Clean();
				bufferOut->Write(0,0);
				return;
					// TODO ERROR
			}
			else
			{
				bufferOut->Write(&nbEncodedData , 1);
			}
		}
		bufferOut->SetEvent(true);
		bufferOut->Write(buffer, nbBytes);
		speex_bits_destroy(&bits);
	}
}

void SpeexEncoder::Decode(void *data, unsigned int size, IBuffer *bufferOut, unsigned short frequence)
{
	short buffer[1280];
	bool first = true;
	SpeexBits bits;
	unsigned int frameSize = (frequence == 32000 ? 1280 : (frequence == 16000 ? 640 : 320));
	void *decoder = GetDecoder(frequence);

	if (!decoder || size < 3)
		return;
	char* nbEncodedData = (char*) data;
	char test = *nbEncodedData;
	
	if (!*nbEncodedData)
		return;
	int offset = 1;
	int packetsize = (size - 1)/(*nbEncodedData);

	if (bufferOut->SizeMax() - bufferOut->Size() < frameSize * (*nbEncodedData))
	{
		bufferOut->Write(0, 0);
		return;
		// ERROR
	}
	speex_bits_init(&bits);
	bufferOut->SetEvent(false);
	while ((*nbEncodedData)-- > 1)
	{
		speex_bits_reset(&bits);
		speex_bits_read_from(&bits, (char*)data + offset, packetsize);
		offset += packetsize;
      /*Decode the data*/
		speex_decode_int(decoder, &bits, buffer);
		bufferOut->Write(buffer, frameSize);
	}

	bufferOut->SetEvent(true);
	speex_bits_reset(&bits);
	speex_bits_read_from(&bits, (char*)data + offset, packetsize);

      /*Decode the data*/
    speex_decode_int(decoder, &bits, buffer);
	bufferOut->Write(buffer, frameSize);
	speex_bits_destroy(&bits);

	//bufferOut->Write(data, size);
}
